package com.xyoto.community.service.impl;

import com.xyoto.community.cache.CacheInstruction;
import com.xyoto.community.dto.PageDTO;
import com.xyoto.community.service.DynamicCacheService;
import com.xyoto.community.service.TopicAllDynamicCacheService;
import com.xyoto.community.utils.PageUtils;
import com.xyoto.community.utils.RedisCommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author coderFu
 * @create 2021/12/2
 */
@Slf4j
@Service
public class TopicAllDynamicCacheServiceImpl implements TopicAllDynamicCacheService {


    @Autowired
    private RedisCommonUtils redisCommonUtils;

    @Autowired
    @Lazy(true)
    private DynamicCacheService dynamicCacheService;

    private final Random random = new Random();

    @Override
    @Async("taskExecutor")
    public void saveNewTopicDynamic(Integer topicId, Integer dynamicId, long timestamp) {
        String key = CacheInstruction.TOPIC_ALL_DYNAMIC + topicId;
        //判断当前容器的大小是否超出最大的限度
        Long size = redisCommonUtils.getZsetSize(key);
        if (size >= CacheInstruction.MAX_COUNT_LIMIT) {
            //如果超出500条，那么实行先进先出原则,将最先进入的删除,默认是升序
            //剔除出第一条
            redisCommonUtils.removeFirstZSetValue(key);
        }
        //加入到缓存中
        redisCommonUtils.zSet(key, dynamicId, (double) timestamp);
    }

    @Override
    @Async("taskExecutor")
    public void deleteTopicAllDynamicForMakePersonal(Integer topicId, Integer dynamicId) {
        String key = CacheInstruction.TOPIC_ALL_DYNAMIC + topicId;
        //判断该动态是否存在缓存中
        boolean flag = redisCommonUtils.judgeZsetExistValue(key, dynamicId);
        if (flag) {
            redisCommonUtils.removeZSetValue(key, dynamicId);
        }
    }

    @Override
    @Async("taskExecutor")
    public void recoverTopicAllDynamic(Integer topicId, Integer dynamicId, long timestamp) {
        saveNewTopicDynamic(topicId, dynamicId, timestamp);
    }

    @Override
    public PageUtils<Integer> getTopicAllDynamicIdListFromCache(Integer topicId, PageDTO pageDTO) {
        String key = CacheInstruction.TOPIC_ALL_DYNAMIC + topicId;
        //查询db中所有话题的动态数目
        int total = dynamicCacheService.getTopicDynamicCount(topicId);
        if (total <= 0) {
            return new PageUtils<>();
        }
        //从话题全部动态缓存中获取动态的id列表
        List<Integer> dynamicList = getTopicDynamicIdsFromCache(key, pageDTO);
        //封装分页信息
        PageUtils<Integer> dynamicPage = new PageUtils<>();
        dynamicPage.setTotal((long) total);
        dynamicPage.setList(dynamicList);
        dynamicPage.setPageNum(pageDTO.getPageNum());
        dynamicPage.setPageSize(pageDTO.getPageSize());
        int totalPage = total % pageDTO.getPageSize() == 0 ? total / pageDTO.getPageSize() : total / pageDTO.getPageSize() + 1;
        dynamicPage.setTotalPage(totalPage);
        return dynamicPage;
    }

    @Override
    @Async("taskExecutor")
    public void deleteTopicAllDynamicById(Integer topicId, Integer dynamicId) {
        this.deleteTopicAllDynamicForMakePersonal(topicId, dynamicId);
    }

    @Override
    public List<Integer> getTopicDynamicIdsFromCache(String key, PageDTO pageDTO) {

        //获取分页相关参数
        int pageNum = pageDTO.getPageNum();
        int pageSize = pageDTO.getPageSize();
        //获取缓存中的位置
        //查询基准点
        int endIndex = pageDTO.getEndIndexId();
        //存储动态id的集合
        ArrayList<Object> dynamicIdList = null;
        //从缓存中获取所有的动态id集合
        Set<Object> dynamicIds = redisCommonUtils.rangeByZSetAll(key);
        dynamicIdList = new ArrayList<>(dynamicIds);

        //获取动态中的索引范围
        int dynamicCount = dynamicIdList.size() - 1;
        //二分查找到小于给定动态id的第一个索引位置
        int targetIndex = getTargetIndex(dynamicIdList, endIndex);

        List<Integer> dynamicIdLists = new ArrayList<>();
        //开始位置
        int start = (pageNum - 1) * pageSize + targetIndex;
        if (start > dynamicCount) {
            return new ArrayList<>();
        }
        int end = start + pageSize - 1;
        int maxIndex = (dynamicCount-start);
        end = Math.min(end, maxIndex);
        for (int i = start; i <= end; i++) {
            Object object = dynamicIdList.get(i);
            if (object != null) {
                dynamicIdLists.add(Integer.valueOf(object.toString()));
            }
        }
        return dynamicIdLists;
    }


    public int getTargetIndex(List<Object> set, int target) {
        if (target == 0) {
            return 0;
        }
        if (set.isEmpty()) {
            return 0;
        } else {
            int leftIndex = 0;
            int rightIndex = set.size() - 1;
            int middleIndex = 0;
            while (leftIndex <= rightIndex) {
                middleIndex = (rightIndex + leftIndex) / 2;
                //判断是否与当前值相等
                if (Integer.parseInt(set.get(middleIndex).toString()) == target) {
                    return middleIndex;
                } else if (Integer.parseInt(set.get(middleIndex).toString()) < target) {
                    rightIndex = middleIndex - 1;
                } else {
                    leftIndex = middleIndex + 1;
                }
            }
            return middleIndex;
        }
    }
}
